/*
 * Copyright (c) 2022  by Junzhao
 * THIS FILE IS PART OF JAVASE Song Huongkang PROJECT
 * All Rights Reserved.
 */

package 使用反射;

import org.junit.Test;
import 结构丰富的Person.Person;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Random;

/**
 * @Description 获取类中的结构
 * @Author 俊昭
 * @Date 2022/5/10
 */
public class ReflectionTest {
    /**
     * 获取一个指定类的实例
     *
     * @param classPath 类的全类名
     */
    public static Object getInstance(String classPath) throws Exception {
        return Class.forName(classPath).newInstance();
    }

    /**
     * 获取运行时类的属性结构
     */
    @Test
    public void test002() {
        // 得到Class对象
        Class<Person> clazz = Person.class;

        // 获取属性结构
        // Field[] getFields() 获取当前运行时类及其父类的public权限属性
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
            /*
            public int 结构丰富的Person.Person.id
            public double 结构丰富的Person.Creature.weight
             */
        }
        System.out.println("\n******我是分割线*****\n");
        // Field[] getFields() 获取当前运行时类自己定义的所有权限属性（不包含父类的）
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field);
            /*
            public int 结构丰富的Person.Person.id
            int 结构丰富的Person.Person.age
            private java.lang.String 结构丰富的Person.Person.name
             */
        }
        System.out.println("\n******我是分割线*****\n");
        // 还可以获取属性的各种信息
        for (Field field : declaredFields) {
            // int getModifiers() 获得权限修饰符
            int modifiers = field.getModifiers();
            System.out.print(modifiers + "\t");
            // String Modifier.toString(int) 将数转换为权限修饰符
            System.out.print(Modifier.toString(modifiers) + "\t");

            // Class getType()数据类型
            Class<?> type = field.getType();
            System.out.print(type + "\t");

            // 变量名
            String name = field.getName();
            System.out.print(name);

            System.out.println();
            /*
            1	public	int	id
            0		int	age
            2	private	class java.lang.String	name
             */
        }
        System.out.println("\n******我是分割线*****\n");
        // 获取方法结构
        // Method[] getMethods() 获取当前运行时类及其继承和实现的所有结构的 public 权限的方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            /*
public int 结构丰富的Person.Person.compare(java.lang.String,java.lang.String)
public int 结构丰富的Person.Person.compare(java.lang.Object,java.lang.Object)
public void 结构丰富的Person.Person.info()
public void 结构丰富的Person.Creature.eat()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
public default java.util.Comparator java.util.Comparator.reversed()
public default java.util.Comparator java.util.Comparator.thenComparing(java.util.function.Function)
public default java.util.Comparator java.util.Comparator.thenComparing(java.util.Comparator)
public default java.util.Comparator java.util.Comparator.thenComparing(java.util.function.Function,java.util.Comparator)
public default java.util.Comparator java.util.Comparator.thenComparingDouble(java.util.function.ToDoubleFunction)
public default java.util.Comparator java.util.Comparator.thenComparingInt(java.util.function.ToIntFunction)
public default java.util.Comparator java.util.Comparator.thenComparingLong(java.util.function.ToLongFunction)
             */
        }
        System.out.println("\n******我是分割线*****\n");
        // Method[] getDeclaredMethods() 获取运行时类自己定义的所有权限的方法（不包含父类的）
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method :declaredMethods) {
            System.out.println(method);
            /*
            public int 结构丰富的Person.Person.compare(java.lang.String,java.lang.String)
            public int 结构丰富的Person.Person.compare(java.lang.Object,java.lang.Object)
            public void 结构丰富的Person.Person.info()
            java.lang.String 结构丰富的Person.Person.display(java.lang.String)
            private java.lang.String 结构丰富的Person.Person.show(java.lang.String)
             */
        }
        System.out.println("\n******我是分割线*****\n");
        // 也可以获取方法的具体结构信息
        for (Method method : declaredMethods) {
            // Annotation[] getAnnotations() 获取方法的注解
            Annotation[] annotations = method.getAnnotations();
            System.out.print(Arrays.toString(annotations)+"\n");
            // 权限修饰符 同属性 见 前
            System.out.print(Modifier.toString(method.getModifiers())+"\t");

            // Class<?> getReturnType() 返回类型
            Class<?> returnType = method.getReturnType();
            System.out.print(returnType.getName()+"\t");

            // 方法名 同属性 见 前
            String name = method.getName();
            System.out.print(name+" (");

            // Class<?>[] getParameterTypes()形参
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 0){
                System.out.print("   ");
            }else{
                //这里就不优化了 口丁乙
                for (int i = 0; i < parameterTypes.length; i++) {
                    System.out.print(parameterTypes[i].getName()+" args_"+i+",");
                }
            }
            System.out.print(")\t");

            // Class<?>[] getExceptionTypes抛出的异常
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            if (exceptionTypes.length != 0){
                //这里就不优化了 口丁乙
                System.out.print("throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    System.out.print(exceptionTypes[i].getName()+i+",");
                }
            }

            System.out.println();
            // 这样我们就获取到了一个方法的所有结构
            // @注解（需要足够的生命周期）
            // 权限修饰符 返回类型 方法名 （形参列表） throws 异常 {}
            /*
[]
public	int	compare(java.lang.String args_0,java.lang.String args_1,)
[]
public volatile	int	compare(java.lang.Object args_0,java.lang.Object args_1,)
[]
public	void	info(   )
[]
	java.lang.String	display(java.lang.String args_0,int args_1,)	throws java.lang.NullPointerException0,java.lang.ClassCastException1,
[@结构丰富的Person.MyAnnotation(value=Hello)]
private	java.lang.String	show(java.lang.String args_0,)
             */
        }
        // 获取运行时类的构造器结构
        // 获取运行时类的父类及其泛型
        // 获取运行时类的接口所在包注解
        // 以上环节跳过                      口丁乙

    }
    @Test
    public void test004() throws Exception {
        Class<Person> clazz = Person.class;
        // 创建运行时类的对象
        Person person = clazz.newInstance();

        // 属性
        // Field getField(String fieldName) 得到对象的指定public权限属性 否则报异常
        // 通常不使用这个方式
        Field id = clazz.getField("id");
        /*
         set(obj，value) 对属性修改
         obj – the object whose field should be modified 需要修改其字段的对象
         value – the new value for the field of obj being modified 对象被修改的字段的新值
         一：操作的对象 二：设置的值
         */
        id.set(person, 1001);

        /*
        Object get(Object obj) 获取obj的指定属性值
         */
        Object o = id.get(person);
        System.out.println(o); // 1001

        // Field getDeclaredField(String fieldName) 得到对象指定属性 不限权限
        Field name = clazz.getDeclaredField("name");

//        name.set(person,"Jerry");// IllegalAccessException
//        System.out.println(name.get(person));
        // 操作之前需要进行一个操作 setAccessible(true) 保证当前属性是可操作的
        name.setAccessible(true);
        //同理
        name.set(person, "Jerry");
        System.out.println(name.get(person)); // Jerry

        // 方法
        // Method getMethod(String methodName,形参列表.class) 同理得到对象的指定public权限方法 否则报异常 不理想不通用

        // Method getDeclaredMethod(String name，<T> parameterTypes) String methodName,形参列表.class
        // name – the name of the method 方法名
        // parameterTypes – the parameter array 形参列表
        Method show = clazz.getDeclaredMethod("show", String.class);
        show.setAccessible(true);// 保证是可操作的
        // 调用 Object invoke(调用方法的对象 ，方法的实参（方法没有实参就没有）) 返回对应类中同名方法的返回值
        Object nation = show.invoke(person, "中国");
        // My nation is 中国
        System.out.println(nation);
        // 中国

        // 调用静态方法
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);

        Object invoke = showDesc.invoke(Person.class);
        System.out.println(invoke);
        // 康胖子是个可爱的人
        // null
        Object invoke1 = showDesc.invoke(null);
        System.out.println(invoke1);
        // 康胖子是个可爱的人
        // null


        // 构造器
        // Constructor<?> getConstructor(形参列表) 同理得到对象的指定public权限构造器 否则报异常 不理想不通用

        Constructor<Person> personConstructor = clazz.getDeclaredConstructor(String.class);
        personConstructor.setAccessible(true);// 保证是可操作的

        Person tom = personConstructor.newInstance("Tom");// 不常用
        System.out.println(tom);
        // Person{id=0, age=0, name='Tom'}


    }

    /**
     * 体会反射的动态性
     */
    @Test
    public void test001() throws Exception {
        for (int i = 0; i < 10; i++) {
            int num = new Random().nextInt(3);//只会出现0,1,2
            switch (num) {
                case 0:
                    System.out.println(getInstance("java.util.Date"));
                    break;
                case 1:
//                System.out.println(getInstance("java.sql.Date").toString());// 没有空参构造器
                    System.out.println(getInstance("java.lang.Object"));
                    break;
                case 2:
                    System.out.println(getInstance("Class类.Person"));
                    break;

                default:
                    break;
            }
        }
//        java.lang.Object@2b05039f
//        Tue May 10 21:30:16 CST 2022
//        Person{name='null', age=0}
//        Person{name='null', age=0}
//        java.lang.Object@66cd51c3
//        Tue May 10 21:30:16 CST 2022
//        Tue May 10 21:30:16 CST 2022
//        Person{name='null', age=0}
//        java.lang.Object@4dcbadb4
//        java.lang.Object@4e515669

    }
}
